package Datenbank;

import java.sql.*;
import java.util.*;
import Applikationslogik.*;
import java.rmi.RemoteException;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * Bildet Objekte des Typs Kalender auf der relationalen Datenbank ab.
 * Die Klasse beinhaltet Methoden und Objekte zum Anlegen, Ändern, Löschen und Suchen.
 *
 * @author Daniel Mossiossian & René van Straaten
 */
public class KalenderMapper {

    private static KalenderMapper kalenderMapper = null;

    /**
     * Stellt sicher, dass nur eine Instanz von KalenderMapper erzeugt wird.
     *
     * @return kalenderMapper das kalenderMapper- Objekt
     */
    public static KalenderMapper KalenderMapper() {
        if (kalenderMapper == null) {
            kalenderMapper = new KalenderMapper();
        }

        return kalenderMapper;
    }

    /**
    * Fügt ein neues Kalender- Objekt in die Datenbank ein.
    * Dabei wird auch überprüft, welche die bisher höhste kalender_id(der Primärschlüssel) ist.
    *
    * @param ka das das zu speichernde Kalender- Objekt
    * @return ka das bereits übergebene Objekt, jedoch mit ggf. korrigierter kalender_id vom Typ Kalender
    */
    public Kalender insert(Kalender ka) {
        Connection con = DBConnection.connection();
        try {
            Statement stmt = con.createStatement();


             //Hier wird überprüft welche kalender_id bisher die höhste ist.

            ResultSet rs = stmt.executeQuery(
                    "SELECT MAX(kalender_id) AS maxid " +
                    "FROM Kalender");
            if (rs.next()) {
                try {
                    // Hier wird die bisher höhste vorhandene kalender_id um 1 erhöht.

                    ka.set_kalender_id(rs.getInt("maxid") + 1);

                    stmt = con.createStatement();

                    // Die tatsächliche Einfügeoperation mit den übergebenden Attributen.


                    // Person ID auslesen
                    int person_id = ka.get_besitzer();

                    stmt.executeUpdate("INSERT INTO Kalender (kalender_id, bezeichnung, besitzer) VALUES (" +
                            ka.get_kalender_id() + ",'" +
                            ka.get_bezeichnung() + "'," +
                            person_id + ")");

                    List <Integer> personenliste_lesen = ka.get_berechtigung_lesen();
                    for (int i = personenliste_lesen.size() - 1; i >= 0; i--) {
                         int ausgabe_lesen = personenliste_lesen.get(i);

                            stmt.executeUpdate("INSERT INTO Berechtigung (person_id, kalender_id, berechtigung) VALUES (" +
                            ausgabe_lesen + "," +
                            ka.get_kalender_id() + "," +
                            "'r'" + ")");
                    }

                    List <Integer> personenliste_schreiben = ka.get_berechtigung_schreiben();
                    for (int i = personenliste_schreiben.size() - 1; i >= 0; i--) {
                         int ausgabe_schreiben = personenliste_schreiben.get(i);

                            stmt.executeUpdate("INSERT INTO Berechtigung (person_id, kalender_id, berechtigung) VALUES (" +
                            ausgabe_schreiben + "," +
                            ka.get_kalender_id() + "," +
                            "'w'" + ")");
                    }
                } catch (Exception ex) {
                    ex.printStackTrace();
                }
            }
        } catch (SQLException e2) {
            e2.printStackTrace();
        }
        // Rückgabe des angelegten Objekts ka von Typ Kalender
        return ka;
    }

    /**
     * Aktualisiert den Kalender in der Datenbank.
     *
     * @param ka das zu aktualisierende Kalender- Objekt
     * @return ka das übergebende Objekt vom Typ Kalender
     */
    public Kalender update(Kalender ka) {
        // Stellt durch Aufruf der connection() Methode der DBConnection-Klasse, die Verbindung zur Datenbank her.
        Connection con = DBConnection.connection();

        try {
            // Leeres SQL-Statement stmt wird angelegt.
            Statement stmt = con.createStatement();

                   stmt.executeUpdate("UPDATE Kalender " +
                    "SET kalender_id=" + ka.get_kalender_id() + ", " +
                    "bezeichnung='" + ka.get_bezeichnung() + "', " +
                    "besitzer=" + ka.get_besitzer() + " " +
                    "WHERE kalender_id=" + ka.get_kalender_id());

            stmt.executeUpdate("DELETE FROM Berechtigung " +
                    "WHERE kalender_id=" + ka.get_kalender_id());

            List <Integer> personenliste_lesen = ka.get_berechtigung_lesen();
                    for (int i = personenliste_lesen.size() - 1; i >= 0; i--) {
                         int ausgabe_lesen = personenliste_lesen.get(i);

                            stmt.executeUpdate("INSERT INTO Berechtigung (person_id, kalender_id, berechtigung) VALUES (" +
                            ausgabe_lesen + "," +
                            ka.get_kalender_id() + "," +
                            "'r'" + ")");
                    }

                    List <Integer> personenliste_schreiben = ka.get_berechtigung_schreiben();
                    for (int i = personenliste_schreiben.size() - 1; i >= 0; i--) {
                         int ausgabe_schreiben = personenliste_schreiben.get(i);

                            stmt.executeUpdate("INSERT INTO Berechtigung (person_id, kalender_id, berechtigung) VALUES (" +
                            ausgabe_schreiben + "," +
                            ka.get_kalender_id() + "," +
                            "'w'" + ")");
                    }

        } catch (SQLException e2) {
            e2.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
        // Das als Parameter übergebende Objekt vom Typ Kalender wird zurückgegeben
        return ka;
    }

    /**
     * Überprüft, ob es für die übergebene Person einen Kalender existiert.
     *
     * @param x das übergebene Person- Objekt vom Typ Person
     * @return true, falls ein Kalender existiert, false falls nicht
     */
    public boolean check_kalender_exists_byperson (Person x){
        int anzahl = 5;
        Connection con = DBConnection.connection();
        try {
            Statement stmt = con.createStatement();


            ResultSet rs = stmt.executeQuery(

                    "SELECT COUNT(*) AS count " +
                    "FROM Kalender " +
                    "WHERE besitzer=" + x.get_person_id());

            while (rs.next()) {
            anzahl = rs.getInt("count");
            }

        } catch (RemoteException ex) {
            Logger.getLogger(KategorieMapper.class.getName()).log(Level.SEVERE, null, ex);
        } catch (SQLException e2) {
            e2.printStackTrace();
        }
        // Wenn es keine Einträge mehr gibt- false zurück, sonst true
        if(anzahl==0)
            return false;
        else
            return true;
    }

    /**
     * Löscht alle Daten eines Kalender- Objekts aus der Datenbank.
     *
     * @param ka ist das zu löschende Objekt
     */
    public void delete(Kalender x) {
        Connection con = DBConnection.connection();

        try {
            // Leeres SQL-Statement stmt wird angelegt.
            Statement stmt = con.createStatement();

            // Statement wird ausgefüllt und als Query an die DB geschickt.
            stmt.executeUpdate("DELETE FROM Kalender " +
                    "WHERE kalender_id=" + x.get_kalender_id());

            stmt.executeUpdate("DELETE FROM Berechtigung " +
            "WHERE kalender_id=" + x.get_kalender_id());

        } catch (SQLException e2) {
            e2.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * Liest alle Personen aus.
     *
     * @return result Vektor mit Personen- Objekten, d.h. allen in der Datenbank
     *         angelegte Personen, zurückgegeben. Bei evtl. Exceptions wird ein
     *         partiell gefüllter oder ggf. auch leerer Vektor vom Typ Kalender zurückgeliefert.
     */
    public Vector findall_person() {
        Connection con = DBConnection.connection();
        Vector result = new Vector();

        try {
            Statement stmt = con.createStatement();


            ResultSet rs = stmt.executeQuery(

                    "SELECT * " +
                    "FROM Person " +
                    "ORDER BY person_id");

            while (rs.next()) {
                try {
                    PersonImpl pe = new PersonImpl();
                    pe.set_person_id(rs.getInt("person_id"));
                    pe.set_raum(rs.getInt("raum"));
                    pe.set_nachname(rs.getString("nachname"));
                    pe.set_vorname(rs.getString("vorname"));
                    pe.set_telefon(rs.getInt("telefon"));
                    pe.set_ist_admin(rs.getBoolean("ist_admin"));
                    pe.set_email(rs.getString("email"));
                    result.addElement(pe);
                    // Wenn kein Titel vorhanden ist, bleibt der String Titel des Vectors leer
                } catch (Exception e) {
                    e.printStackTrace();
                    //Bei einer evtl. Exception wird die while-Schleife abgebrochen.
                    break;
                }

            }
        } catch (SQLException e2) {
            e2.printStackTrace();
        }
        // Ergebnisvektor wird zurückgeben.
        return result;
    }

    /**
     * Sucht in der Datenbank nach einem Kalender mit der eingegebenen ID.
     *
     * @param id ist das Primärschlüsselattribut Kalender in der Datenbank
     * @return Das Objekt vom Typ Kalender, das der id entspricht wird zurückgegebn.
     *         null wird zurückgegeben, wenn das Objekt nicht in der Datenbank vorhanden ist.
     *         Da es sich um einen Primärschlüssel handelt und dieser somit eindeutig ist, wird genau ein Objekt zurückgegeben.
     */
    public Kalender findbyid(int id) {
        Connection con = DBConnection.connection();

        try {
            Statement stmt = con.createStatement();

            ResultSet rs = stmt.executeQuery(
                    "SELECT * FROM Kalender " +
                    "WHERE kalender_id =" + id);

            /*
             * Da es sich bei id um einen Primärschlüssel handelt, kann max. nur ein Tupel zurückgegeben werden.
             * Es wird geprüft, ob ein Ergebnis vorliegt. Wenn ja werden die Attribute kalender_id,
             * besitzer und bezeichnung ausgelesen und als Typ Kalender zurückgegeben.
             */
            if (rs.next()) {
                try {
                    System.out.println(id);
                    KalenderImpl ka = new KalenderImpl();
                    ka.set_kalender_id(rs.getInt("kalender_id"));
                    ka.set_bezeichnung(rs.getString("bezeichnung"));
                    ka.set_besitzer(rs.getInt("besitzer"));

                    try {
                        Statement stmt2 = con.createStatement();

                        ResultSet rs2 = stmt2.executeQuery(
                                "SELECT person_id FROM Berechtigung " +
                                "WHERE kalender_id =" + id + " AND berechtigung='r'");



                        List<Integer> personenliste_lesen = new ArrayList<Integer>();
                        System.out.println("Es folgen die ausgelesenen Leseberechtigungen:");
                        while (rs2.next()) {
                            try {
                                System.out.println(rs2.getInt("person_id"));
                                personenliste_lesen.add(rs2.getInt("person_id"));
                                ka.set_berechtigung_lesen(personenliste_lesen);

                            } catch (Exception e) {
                                e.printStackTrace();
                                return null;
                            }
                        }

                    } catch (SQLException e2) {
                        e2.printStackTrace();
                        return null;
                    }



                    try {
                        Statement stmt3 = con.createStatement();

                        ResultSet rs3 = stmt3.executeQuery(
                                "SELECT person_id FROM Berechtigung " +
                                "WHERE kalender_id =" + id + " AND berechtigung='w'");



                        List<Integer> personenliste_schreiben = new ArrayList<Integer>();
                        System.out.println("");
                        System.out.println("Es folgen die ausgelesenen Schreibberechtigungen:");
                        while (rs3.next()) {
                            try {
                                System.out.println(rs3.getInt("person_id"));
                                personenliste_schreiben.add(rs3.getInt("person_id"));
                                ka.set_berechtigung_schreiben(personenliste_schreiben);
                            }

                            catch (Exception e) {
                                e.printStackTrace();
                                return null;
                            }
                        }
                        return ka;
                    } catch (SQLException e2) {
                        e2.printStackTrace();
                        return null;
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                    return null;
                }
            }
        } catch (SQLException e2) {
            e2.printStackTrace();
            return null;
        }
        return null;
    }

    /**
     * Sucht in der Datenbank nach allen Kalendern von einer Person
     * mit der eingegebenen ID.
     *
     * @param person_id die ID der Person
     * @return result Ergebnisvektor mit den Kalendern von der Person
     */
    public Vector findallKalender_byPerson(int person_id) {
        Connection con = DBConnection.connection();
        Vector <Kalender> result = new Vector();

        try {
            Statement stmt = con.createStatement();
            ResultSet rs = stmt.executeQuery(
                    "SELECT * FROM Kalender " +
                    "WHERE besitzer =" + person_id);

            /*
             * Da es sich bei id um einen Primärschlüssel handelt, kann max. nur ein Tupel zurückgegeben werden.
             * Es wird geprüft, ob ein Ergebnis vorliegt. Wenn ja werden die Attribute kalender_id,
             * bezeichnung und besitzer ausgelesen.
             */
            while (rs.next()) {
                try {
                    KalenderImpl ka = new KalenderImpl();
                    ka.set_kalender_id(rs.getInt("kalender_id"));
                    ka.set_bezeichnung(rs.getString("bezeichnung"));
                    ka.set_besitzer(rs.getInt("besitzer"));
                    try {
                        Statement stmt2 = con.createStatement();

                        ResultSet rs2 = stmt2.executeQuery(
                                "SELECT person_id FROM Berechtigung " +
                                "WHERE kalender_id =" + ka.get_kalender_id() + " AND berechtigung='r'");



                        List<Integer> personenliste_lesen = new ArrayList<Integer>();
                        System.out.println("Es folgen die ausgelesenen Leseberechtigungen:");
                        while (rs2.next()) {
                            try {
                                System.out.println(rs2.getInt("person_id"));
                                personenliste_lesen.add(rs2.getInt("person_id"));
                                ka.set_berechtigung_lesen(personenliste_lesen);

                            } catch (Exception e) {
                                e.printStackTrace();
                                return null;
                            }
                        }

                    } catch (SQLException e2) {
                        e2.printStackTrace();
                        return null;
                    }
                    try {
                        Statement stmt3 = con.createStatement();

                        ResultSet rs3 = stmt3.executeQuery(
                                "SELECT person_id FROM Berechtigung " +
                                "WHERE kalender_id =" + ka.get_kalender_id() + " AND berechtigung='w'");

                        List<Integer> personenliste_schreiben = new ArrayList<Integer>();
                        System.out.println("");
                        System.out.println("Es folgen die ausgelesenen Schreibberechtigungen:");
                        while (rs3.next()) {
                            try {
                                System.out.println(rs3.getInt("person_id"));
                                personenliste_schreiben.add(rs3.getInt("person_id"));
                                ka.set_berechtigung_schreiben(personenliste_schreiben);
                            }
                            catch (Exception e) {
                                e.printStackTrace();
                                return null;
                            }
                        }
                       result.addElement(ka);

                    } catch (SQLException e2) {
                        e2.printStackTrace();
                        return null;
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                    return null;
                }
            }
        } catch (SQLException e2) {
            e2.printStackTrace();
            return null;
        }

        return result;
    }

    /**
     * Sucht in der Datenbank nach allen Kalendern für eine Person mit der
     * eingegebenen ID der Person. Es werden nur diejenigen Kalender ausgelesen,
     * für die die Person eine Berechtigung hat.
     *
     * @param person_id ID der Person vom Typ int
     * @return result Ergebnisvektor mit allen Kalendern
     */
    public Vector findallKalender_byBerechtigung(int person_id) {
        Connection con = DBConnection.connection();
        Vector <Kalender> result = new Vector();

        try {
            Statement stmt = con.createStatement();

            ResultSet rs = stmt.executeQuery(
                    "SELECT * FROM Kalender INNER JOIN Berechtigung ON Kalender.kalender_id = Berechtigung.kalender_id " +
                    "WHERE person_id =" + person_id + " AND berechtigung='w' ORDER BY person_id");

            while (rs.next()) {
                try {
                    KalenderImpl ka = new KalenderImpl();
                    ka.set_kalender_id(rs.getInt("kalender_id"));
                    ka.set_bezeichnung(rs.getString("bezeichnung"));
                    ka.set_besitzer(rs.getInt("besitzer"));

                    try {
                        Statement stmt2 = con.createStatement();

                        ResultSet rs2 = stmt2.executeQuery(
                                "SELECT person_id FROM Berechtigung " +
                                "WHERE kalender_id =" + ka.get_kalender_id() + " AND berechtigung='r'");


                        List<Integer> personenliste_lesen = new ArrayList<Integer>();
                        System.out.println("Es folgen die ausgelesenen Leseberechtigungen:");
                        while (rs2.next()) {
                            try {
                                System.out.println(rs2.getInt("person_id"));
                                personenliste_lesen.add(rs2.getInt("person_id"));
                                ka.set_berechtigung_lesen(personenliste_lesen);

                            } catch (Exception e) {
                                e.printStackTrace();
                                return null;
                            }
                        }

                    } catch (SQLException e2) {
                        e2.printStackTrace();
                        return null;
                    }
                    try {
                        Statement stmt3 = con.createStatement();

                        ResultSet rs3 = stmt3.executeQuery(
                                "SELECT person_id FROM Berechtigung " +
                                "WHERE kalender_id =" + ka.get_kalender_id() + " AND berechtigung='w'");


                        List<Integer> personenliste_schreiben = new ArrayList<Integer>();
                        System.out.println("");
                        System.out.println("Es folgen die ausgelesenen Schreibberechtigungen:");
                        while (rs3.next()) {
                            try {
                                System.out.println(rs3.getInt("person_id"));
                                personenliste_schreiben.add(rs3.getInt("person_id"));
                                ka.set_berechtigung_schreiben(personenliste_schreiben);
                            }

                            catch (Exception e) {
                                e.printStackTrace();
                                return null;
                            }
                        }
                       result.addElement(ka);

                    } catch (SQLException e2) {
                        e2.printStackTrace();
                        return null;
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                    return null;
                }
            }
        } catch (SQLException e2) {
            e2.printStackTrace();
            return null;
        }
        return result;
    }

    /**
     * Checkt die Kalender auf existierende Teilnahme.
     *
     * @param x das zu überprüfende Kalender- Objekt
     * @return true, falls Teinahme existiert, sonst false
     */
    public boolean check_kalender_exists_byteilnahme (Kalender x) {
        int anzahl = 5;
        Connection con = DBConnection.connection();
        try {
            Statement stmt = con.createStatement();
            ResultSet rs = stmt.executeQuery(
                    "SELECT COUNT(*) AS count " +
                    "FROM Teilnahme " +
                    "WHERE kalender_id=" + x.get_kalender_id() + " AND teilnahme=1");
            while (rs.next()) {
            anzahl = rs.getInt("count");
            }
        } catch (RemoteException ex) {
            Logger.getLogger(KategorieMapper.class.getName()).log(Level.SEVERE, null, ex);
        } catch (SQLException e2) {
            e2.printStackTrace();
        }
        // Wenn es keine Einträge mehr gibt- false, sonst true
        System.out.println("------------ check_kalender_exists_byteilnahme ----------------");
        System.out.println("Anzahl der noch verknüpften Kalender: "+anzahl);
        if(anzahl==0)
            return false;
        else
            return true;
    }

    /**
     * Gibt alle Kalender, für die die eingeloggte Person eine Berechtigung hat, zurück.
     *
     * @param eingeloggte_person die eingeloggte Person vom Typ Person
     * @param x Vektor
     * @return result Ergebnisvektor mit allen Kalendern
     */
    public Vector <Kalender> get_kalender_reporter(Person eingeloggte_person, Vector <Kalender> x) {
        Vector <Kalender> result = new Vector();
        for(int i=0; i < x.size(); i++)
        {
                try {
                    int kalender_id = x.elementAt(i).get_kalender_id();
                    int person_id = eingeloggte_person.get_person_id();
                    int anzahl = 0;
                        Connection con = DBConnection.connection();
                        try {
                            Statement stmt = con.createStatement();

                            anzahl=0;
                            ResultSet rs = stmt.executeQuery(
                                    "SELECT COUNT(*) AS count " +
                                    "FROM Berechtigung " +
                                    "WHERE kalender_id=" + kalender_id + " AND " + "person_id=" + person_id);

                            while (rs.next()) {
                            anzahl = rs.getInt("count");
                            }
                            if(anzahl != 0)
                                result.add(x.elementAt(i));
                        }  catch (SQLException e2) {
                            e2.printStackTrace();
                        }
                } catch (RemoteException ex) {
                    Logger.getLogger(KalenderMapper.class.getName()).log(Level.SEVERE, null, ex);
                }
        }
        return result;
    }
}

